#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/io.h>
struct device_test{
	dev_t dev_num; //设备号
	int major ; //主设备号
	int minor ; //次设备号
	struct cdev cdev_test; // cdev
	struct class *class; //类
	struct device *device; //设备
	char kbuf[32];
	unsigned int *vir_gpio_dr;
};
struct device_test dev1;
/*打开设备函数*/
static int cdev_test_open(struct inode *inode, struct file *file)
{
	file->private_data=&dev1;//设置私有数据
	printk("This is cdev_test_open\r\n");
	return 0;
}
/*向设备写入数据函数*/
static ssize_t cdev_test_write(struct file *file, const char __user *buf, size_t size, loff_t *off)
{
	struct device_test *test_dev=(struct device_test *)file->private_data;
	if (copy_from_user(test_dev->kbuf, buf, size) != 0) // copy_from_user:用户空间向内核空间传数据
	{
		printk("copy_from_user error\r\n");
		return -1;
	}
	if(test_dev->kbuf[0]==1){ //如果应用层传入的数据是 1，则打开灯
		*(test_dev->vir_gpio_dr) = 0x8000c040; //设置数据寄存器的地址
		printk("test_dev->kbuf [0] is %d\n",test_dev->kbuf[0]); //打印传入的数据
	}
	else if(test_dev->kbuf[0]==0) //如果应用层传入的数据是 0，则关闭灯
	{
		*(test_dev->vir_gpio_dr) = 0x80004040; //设置数据寄存器的地址
		printk("test_dev->kbuf [0] is %d\n",test_dev->kbuf[0]); //打印传入的数据
	}
	return 0;
}
/**从设备读取数据*/
static ssize_t cdev_test_read(struct file *file, char __user *buf, size_t size, loff_t *off)
{
	struct device_test *test_dev=(struct device_test *)file->private_data;
	if (copy_to_user(buf, test_dev->kbuf, strlen( test_dev->kbuf)) != 0) // copy_to_user:内核空间向用户空间传数据
{
		printk("copy_to_user error\r\n");
		return -1;
	}
	printk("This is cdev_test_read\r\n");
	return 0;
}
static int cdev_test_release(struct inode *inode, struct file *file)
{
	printk("This is cdev_test_release\r\n");
	return 0;
}
/*设备操作函数*/
struct file_operations cdev_test_fops = {
	.owner = THIS_MODULE, //将 owner 字段指向本模块，可以避免在模块的操作正在被使用时卸载该模块
	.open = cdev_test_open, //将 open 字段指向 chrdev_open(...)函数
	.read = cdev_test_read, //将 open 字段指向 chrdev_read(...)函数
	.write = cdev_test_write, //将 open 字段指向 chrdev_write(...)函数
	.release = cdev_test_release, //将 open 字段指向 chrdev_release(...)函数
};
static int my_platform_driver_probe(struct platform_device *pdev)
{
	struct resource *res_mem;int ret;
	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res_mem) {
		dev_err(&pdev->dev, "Failed to get memory resource\n");
		return -ENODEV;
	}
/*注册字符设备驱动*/
/*1 创建设备号*/
ret = alloc_chrdev_region(&dev1.dev_num, 0, 1, "alloc_name"); //动态分配设备号		
	if (ret < 0){
		goto err_chrdev;
	}
	printk("alloc_chrdev_region is ok\n");
	dev1.major = MAJOR(dev1.dev_num); //获取主设备号
	dev1.minor = MINOR(dev1.dev_num); //获取次设备号
	printk("major is %d \r\n", dev1.major); //打印主设备号
	printk("minor is %d \r\n", dev1.minor); //打印次设备号
/*2 初始化 cdev*/
dev1.cdev_test.owner = THIS_MODULE;
cdev_init(&dev1.cdev_test, &cdev_test_fops);
/*3 添加一个 cdev,完成字符设备注册到内核*/
ret = cdev_add(&dev1.cdev_test, dev1.dev_num, 1);
	if(ret<0)
	{
		goto err_chr_add;
	}
/*4 创建类*/
dev1. class = class_create(THIS_MODULE, "test");
	if(IS_ERR(dev1.class))
	{
		ret=PTR_ERR(dev1.class);
		goto err_class_create;
	}
/*5 创建设备*/
dev1.device = device_create(dev1.class, NULL, dev1.dev_num, NULL, "test");
	if(IS_ERR(dev1.device))
	{
		ret=PTR_ERR(dev1.device);
		goto err_device_create;
	}
dev1.vir_gpio_dr=ioremap(res_mem->start,4); //将物理地址转化为虚拟地址		
	if(IS_ERR(dev1.vir_gpio_dr))
	{
		ret=PTR_ERR(dev1.vir_gpio_dr); //PTR_ERR()来返回错误代码
		goto err_ioremap;
	}
return 0;

err_ioremap:
	iounmap(dev1.vir_gpio_dr);
err_device_create:
	class_destroy(dev1.class);//删除类
err_class_create:
	cdev_del(&dev1.cdev_test);//删除 cdev
err_chr_add:
	unregister_chrdev_region(dev1.dev_num, 1); //注销设备号
err_chrdev:
	return ret;
}
static int my_platform_driver_remove(struct platform_device *pdev)
{
	// 设备移除操作
	return 0;
}
static struct platform_driver my_platform_driver = {
	.driver = {
		.name ="my_platform_device", // 与 platform_device.c 中的设备名称匹配
		.owner = THIS_MODULE,
	},
	.probe = my_platform_driver_probe,
	.remove = my_platform_driver_remove,
};
static int __init my_platform_driver_init(void)
{
	int ret;
	ret = platform_driver_register(&my_platform_driver); // 注册平台驱动
	if (ret) {
		printk("Failed to register platform driver\n");
		return ret;
	}
	printk("Platform driver registered\n");
	return 0;
}
static void __exit my_platform_driver_exit(void)
{
/*注销字符设备*/
	unregister_chrdev_region(dev1.dev_num, 1); //注销设备号
	cdev_del(&dev1.cdev_test);//删除 cdev
	device_destroy(dev1.class, dev1.dev_num); //删除设备
	class_destroy(dev1.class);//删除类
	platform_driver_unregister(&my_platform_driver); // 注销平台驱动
	printk("Platform driver unregistered\n");
}
module_init(my_platform_driver_init);
module_exit(my_platform_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("topeet");
